package org.blogsomy.jaas;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

import org.apache.commons.codec.digest.DigestUtils;
import org.blogsomy.model.dao.DaoFacade;
import org.blogsomy.model.dao.UserDao;
import org.blogsomy.model.entities.User;
import org.springframework.context.ApplicationContext;

import com.google.code.lightsomy.web.ApplicationContextRegistry;

public class BlogsomyLoginModule implements LoginModule {

	private Subject subject;
	
	private CallbackHandler callbackHandler;
	
	@SuppressWarnings("unused")
	private Map<String, ?> sharedState;
	
	@SuppressWarnings("unused")
	private Map<String, ?> options;
	
	private List<Principal> principals;
	
	private boolean success;
	
	public BlogsomyLoginModule() {
		principals = new ArrayList<Principal>();
		success = false;
	}
	
	@Override
	public void initialize(Subject subject, CallbackHandler callbackHandler,
			Map<String, ?> sharedState, Map<String, ?> options) {
		this.subject = subject;
		this.callbackHandler = callbackHandler;
		this.sharedState = sharedState;
		this.options = options;
	}

	@Override
	public boolean login() throws LoginException {
		if (callbackHandler == null) {
			throw new LoginException("Handler is null");
		}

		try {
			Callback[] callbacks = new Callback[] {
					new NameCallback("User: "),
					new PasswordCallback("Password: ", false)
			};
			
			callbackHandler.handle(callbacks);
			
			String username = ((NameCallback) callbacks[0]).getName();
	        String password = new String(((PasswordCallback) callbacks[1]).getPassword());

			success = autenticate(username, password);
			return success;
		} catch (Exception e) {
			e.printStackTrace();
			throw new LoginException(e.getMessage());
		}
	}
	
	@Override
	public boolean commit() throws LoginException {
		if (success) {
			if (subject.isReadOnly()) {
				throw new LoginException("Subject is read-only, can't commit");
			}

			try {
				subject.getPrincipals().addAll(principals);
				principals.clear();
				return true;
			} catch (Exception e) {
				throw new LoginException(e.getMessage());
			}
		}

		principals.clear();
		return false;
	}

	@Override
	public boolean logout() throws LoginException {
		try {
			principals.clear();
			Iterator<BlogsomyRole> iterator = subject.getPrincipals(
					BlogsomyRole.class).iterator();
	
			while (iterator.hasNext()) {
				BlogsomyRole p = (BlogsomyRole) iterator.next();
				subject.getPrincipals().remove(p);
			}
		} catch (Throwable e) {
			throw new LoginException(e.getMessage());
		}

		return true;
	}

	@Override
	public boolean abort() throws LoginException {
		if (!success) {
			return false;
		}
		
		principals.clear();
		logout();
		return true;
	}
	
	private boolean autenticate(String username, String password) {
		ApplicationContext ac = ApplicationContextRegistry.getApplicationContext();
		DaoFacade facade = (DaoFacade) ac.getBean("daoFacade");
		UserDao userDao = facade.getUserDao();
		User u = userDao.find(username, DigestUtils.shaHex(password));
		
		if (u != null) {
			principals.add(new BlogsomyRole("admin"));
			principals.add(u);
			return true;
		}

		return false;
	}

}
